package com.gitee.wsl.ext.map

import com.gitee.wsl.ext.collection.removeEmpty
import com.gitee.wsl.ext.set.removeIf

fun <K, V> MutableMap<K, V>.removeIf(block: Map.Entry<K, V>.() -> Boolean): MutableMap<K, V> {
    this.entries.removeIf (block)
    return this
}

/**
 * Removes any values in the map that are not type [V] and
 * returns a [MutableMap]<[K], [V]> with the remaining entries.
 */
@Suppress("UNCHECKED_CAST")
inline fun <K, reified V> MutableMap<K, *>.removeValuesUnlessInstanceOf(): MutableMap<K, V> =
    (this as MutableMap<Any, Any>).mutateValuesNotNull { (_, value) -> value as? V } as MutableMap<K, V>


/**
 * Removes entries from this mutable map if they satisfy the given predicate.
 *
 * The predicate takes a key-value pair and returns true if the entry should be removed. This method
 * iterates over the entries of the map and applies the predicate to each entry, removing those that match.
 * This allows for flexible and efficient bulk removal based on custom criteria.
 *
 * @param predicate a function that evaluates each key-value pair and returns true for entries to be removed.
 */
//@Suppress("kotlin:S6524")
//inline fun <K, V> MutableMap<K, V>.removeIf(predicate: (K, V) -> Boolean) {
//    val iterator = entries.iterator()
//    while (iterator.hasNext()) {
//        val entry = iterator.next()
//        if (predicate(entry.key, entry.value)) {
//            iterator.remove()
//        }
//    }
//}


/**
 * Extension function for removing empty maps and collections from a Map.
 *
 * Returns a new map with empty maps and collections removed.
 *
 * @param maps If true, empty maps will be removed. Default is true.
 * @param collections If true, empty collections will be removed. Default is true.
 * @return A new map with empty maps and collections removed.
 */
fun <K, V> Map<K, V>.removeEmpty(
    maps: Boolean = true,
    collections: Boolean = true
): Map<K, V> {
    if (!maps && !collections) return this

    val result = mutableMapOf<K, V>()
    for ((key, value) in this) {
        when {
            maps && value is Map<*, *> -> {
                val cleanedMap = value.removeEmpty(true, collections)
                if (cleanedMap.isNotEmpty()) {
                    @Suppress("UNCHECKED_CAST")
                    result[key] = cleanedMap as V
                }
            }
            collections && value is Iterable<*> -> {
                val cleanedCollection = value.removeEmpty(maps, true)
                if (cleanedCollection.isNotEmpty()) {
                    @Suppress("UNCHECKED_CAST")
                    result[key] = cleanedCollection as V
                }
            }
            else -> result[key] = value
        }
    }
    return result
}


/**
 * Call [block] for each entry in the map and clear the map
 *
 * @param block block to call for each entry
 */
inline fun <K, V> MutableMap<K, V>.clear(block: Map.Entry<K, V>.() -> Unit) {
    forEach {
        block(it)
    }
    clear()
}